/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;

namespace GrooveWebServicesV12Helpers
{
	/// <summary>
	/// A class describing a Groove Account, and its Contacts and Messages.
	/// 
	/// Usually you will access accounts on the current machine by enumerating the
	/// array returned from the static method Account.GetAccounts().
	/// </summary>
	public class Account : 
		GrooveWebServicesV12HelpersBase,
		GrooveWebServicesV12Helpers.Shared.IGrooveWebServicesEventCallback
	{
		private GrooveAccountsWebService.Account2 m_Account;
		private GrooveAccountsWebService.GrooveAccounts m_GrooveAccounts;
		private GrooveContactsWebService.GrooveContacts m_GrooveContacts;
		private GrooveMessagesWebService.GrooveMessages m_GrooveMessages;

		private GrooveWebServicesV12Helpers.Identity[] m_Identities;
		private GrooveWebServicesV12Helpers.Service[] m_AdditionalServices;

		private string m_ContactSubscriptionID;
		private string m_MessageSubscriptionID;

		internal static System.Collections.SortedList s_ContactEventManagerSortedList = new System.Collections.SortedList();
		internal static System.Collections.SortedList s_MessageEventManagerSortedList = new System.Collections.SortedList();

		//  These variable would normally be a bool, but you can't use the
		//  'lock' keyword with scalar types, so we declare it as an object
		private object m_IdentitiesInitialized;

		private int m_ContactEventManagerCount = 0;
		private int m_MessageEventManagerCount = 0;

		public Account(GrooveAccountsWebService.Account2 i_Account, GrooveWebServicesV12Helpers.Context i_Context)
			: base(i_Account.Name, i_Account.URI, i_Account.Identities[0].URI, i_Context)
		{
			m_Account = i_Account;
			m_IdentitiesInitialized = false;
		}

		#region Account Properties and Methods

		public static GrooveAccountsWebService.GrooveAccounts CreateInitializedAccountsWebService(string i_TargetURI, GrooveWebServicesV12Helpers.Context i_Context)
		{
			//  Create the service
			GrooveAccountsWebService.GrooveAccounts AccountsWebService = new GrooveAccountsWebService.GrooveAccounts();

			//  Create the Groove SOAP header
			AccountsWebService.GrooveRequestHeaderValue = new GrooveAccountsWebService.GrooveRequestHeader();

			//  Set appropriate header values
			AccountsWebService.GrooveRequestHeaderValue.GrooveRequestKey = i_Context.RequestKey;

			//  Set the URL
			AccountsWebService.Url = i_Context.Host + i_TargetURI;

			//  Set Timeout
			AccountsWebService.Timeout = i_Context.Timeout;

			return AccountsWebService;
		}

		/// <summary>
		/// Returns an array of Accounts in the current Groove instance.
		/// </summary>
		/// <param name="i_Context">The Web Services Context.</param>
		/// <returns>Array of Accounts</returns>
		public static GrooveWebServicesV12Helpers.Account[] GetAccounts(GrooveWebServicesV12Helpers.Context i_Context)
		{
			//  Get initialized reference to web service
			GrooveAccountsWebService.GrooveAccounts AccountsWebService = GrooveWebServicesV12Helpers.Account.CreateInitializedAccountsWebService
				(
				GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_ACCOUNTS_URI,
				i_Context
				);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to provide the list of accounts on this device.
			GrooveAccountsWebService.Account2[] Accounts = AccountsWebService.Read2();

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("AccountsWebService::Read, " + TimeSpan.TotalMilliseconds + " ms");
			}

			//  Create array list of accounts
			System.Collections.ArrayList AccountArrayList = new System.Collections.ArrayList();
			foreach (GrooveAccountsWebService.Account2 Account in Accounts)
			{
				try
				{
					GrooveWebServicesV12Helpers.Account NewAccount = new GrooveWebServicesV12Helpers.Account
						(
						Account,
						i_Context
						);

					AccountArrayList.Add(NewAccount);
				}
				catch (System.Exception Exception)
				{
					string Message = System.String.Format
                        (
                        "GetAccounts couldn't open Account {0}. Encountered exception {1}.",
						Account.Name, 
                        Exception.Message
                        );

					System.Diagnostics.Debug.WriteLine(Message);
				}
			}

			//  Return array from array list
			return (GrooveWebServicesV12Helpers.Account[])AccountArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Account));
		}

		/// <summary>
		/// Returns an array of the Identities in this Account.
		/// </summary>
		public GrooveWebServicesV12Helpers.Identity[] Identities
		{
			get
			{
				lock (m_IdentitiesInitialized)
				{
					if (!(bool)m_IdentitiesInitialized)
					{
						//  Create array list of identities
						System.Collections.ArrayList IdentityArrayList = new System.Collections.ArrayList();
						foreach (GrooveAccountsWebService.Identity2 Identity in m_Account.Identities)
						{
							GrooveWebServicesV12Helpers.Identity NewIdentity = new GrooveWebServicesV12Helpers.Identity
								(
								this,
								Identity
								);

							IdentityArrayList.Add(NewIdentity);
						}

						//  ----------------------------------------------------------------------------------------
						//  BIG HONKING NOTE:  We assume that identities change infrequently, so we are caching them
						//  ----------------------------------------------------------------------------------------

						//  Return array from array list
						m_Identities = (GrooveWebServicesV12Helpers.Identity[])IdentityArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Identity));
						m_IdentitiesInitialized = true;
					}
				}

				return m_Identities;
			}
		}

		/// <summary>
		/// Returns an array of the Services provided in this Account.
		/// </summary>
		public GrooveWebServicesV12Helpers.Service[] AdditionalServices
		{
			get
			{
				if (m_AdditionalServices == null)
				{
					System.Collections.ArrayList ServiceArrayList = new System.Collections.ArrayList();
 
					foreach (GrooveAccountsWebService.Service Service in m_Account.AdditionalServices)
					{
						GrooveWebServicesV12Helpers.Service NewService = new GrooveWebServicesV12Helpers.Service(Service);
						ServiceArrayList.Add(NewService);
					}

					//  Convert array list to array
					m_AdditionalServices = (GrooveWebServicesV12Helpers.Service[])ServiceArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Service));
				}

				return m_AdditionalServices;
			}
		}

		private GrooveAccountsWebService.GrooveAccounts GetInitializedAccountsWebService(string i_TargetURI, GrooveWebServicesV12Helpers.Context i_Context)
		{
            if ((m_GrooveAccounts == null) || Context.ReinitNeeded(m_GrooveAccounts.GrooveRequestHeaderValue.GrooveRequestKey))
			{
				m_GrooveAccounts = GrooveWebServicesV12Helpers.Account.CreateInitializedAccountsWebService
					(
					i_TargetURI,
					i_Context
					);
			}
			else
			{
				//  Explicitly overwrite target URL and Timeout
				m_GrooveAccounts.Url = i_Context.Host + i_TargetURI;
                m_GrooveAccounts.Timeout = i_Context.Timeout;
			}

			return m_GrooveAccounts;
		}


		#endregion

		#region Contact Properties and Methods

		/// <summary>
		/// Returns an array of Contacts in this Account's personal contact list.
		/// </summary>
		public GrooveWebServicesV12Helpers.Contact[] PersonalContacts
		{
			get
			{
				System.Collections.ArrayList PersonalContactArrayList = new System.Collections.ArrayList();

				GrooveContactsWebService.Contact[] Contacts = int_GetContacts(GrooveWebServicesV12Helpers.Shared.GROOVE_PERSONAL_CONTACT_TYPE);

				//  Populate array list of Contacts
				foreach (GrooveContactsWebService.Contact Contact in Contacts)
				{
					GrooveWebServicesV12Helpers.Contact NewContact = new GrooveWebServicesV12Helpers.Contact 
						(
						this,
						Contact
						);

					PersonalContactArrayList.Add(NewContact);
				}

				//  Return array from array list
				return (GrooveWebServicesV12Helpers.Contact[])PersonalContactArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Contact));
			}
		}

		/// <summary>
		/// Returns an array of Contacts in this Account's workspaces.
		/// </summary>
		public GrooveWebServicesV12Helpers.Contact[] SharedSpaceContacts
		{
			get
			{
				System.Collections.ArrayList TelespaceMemberContactArrayList = new System.Collections.ArrayList();

				GrooveContactsWebService.Contact[] Contacts = int_GetContacts(GrooveWebServicesV12Helpers.Shared.GROOVE_TELESPACE_MEMBER_CONTACT_TYPE);

				//  Populate array list of Contacts
				foreach (GrooveContactsWebService.Contact Contact in Contacts)
				{
					GrooveWebServicesV12Helpers.Contact NewContact = new GrooveWebServicesV12Helpers.Contact 
						(
						this,
						Contact
						);

					TelespaceMemberContactArrayList.Add(NewContact);
				}

			//  Return array from array list
			return (GrooveWebServicesV12Helpers.Contact[])TelespaceMemberContactArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Contact));
			}
		}

		private GrooveContactsWebService.Contact[] int_GetContacts(string i_ContactType)
		{
			//  Get initialized reference to web service
			GrooveContactsWebService.GrooveContacts ContactsWebService = this.GetInitializedContactsWebService(m_Account.Contacts);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to provide the list of Contacts on this device.
			GrooveContactsWebService.Contact[] Contacts = ContactsWebService.Read(i_ContactType);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("ContactsWebService::Read, " + TimeSpan.TotalMilliseconds + " ms");
			}

			return Contacts;
		}

		/// <summary>
		/// Finds a Contact, by URI, from this Account's personal contact list.
		/// </summary>
		/// <param name="i_ContactURI">The contact URI.</param>
		/// <param name="o_Contact">The contact.</param>
		/// <returns>true if the contact was found.</returns>
		public bool FindPersonalContact(string i_ContactURI, out GrooveWebServicesV12Helpers.Contact o_Contact)
		{
			bool Found = false;
			o_Contact = null;

			//  ----------------------------------------------------------------------------
			//  HACK ALERT:  Until there is a method to read one contact, we have to get all
			//               contacts and search for match

				GrooveWebServicesV12Helpers.Contact[] Contacts = this.PersonalContacts;
				foreach (GrooveWebServicesV12Helpers.Contact Contact in Contacts)
				{
					if (Contact.URI == i_ContactURI)
					{
						Found = true;
						o_Contact = Contact;

						break;
					}
				}

			//  ----------------------------------------------------------------------------

			return Found;
		}

		/// <summary>
		/// Finds a Contact, by URI, from this Account's workspace contacts list.
		/// </summary>
		/// <param name="i_ContactURI">The contact URI.</param>
		/// <param name="o_Contact">The contact.</param>
		/// <returns>true if the contact was found.</returns>
		public bool FindSharedSpaceContact(string i_ContactURI, out GrooveWebServicesV12Helpers.Contact o_Contact)
		{
			bool Found = false;
			o_Contact = null;

			//  ----------------------------------------------------------------------------
			//  HACK ALERT:  Until there is a method to read one contact, we have to get all
			//               contacts and search for match

				GrooveWebServicesV12Helpers.Contact[] Contacts = this.SharedSpaceContacts;
				foreach (GrooveWebServicesV12Helpers.Contact Contact in Contacts)
				{
					if (Contact.URI == i_ContactURI)
					{
						Found = true;
						o_Contact = Contact;

						break;
					}
				}

			//  ----------------------------------------------------------------------------

			return Found;
		}

		/// <summary>
		/// Returns the URI for raw access to Contacts web services in this Account
		/// </summary>
		public string ContactsURI
		{
			get
			{
				return m_Account.Contacts;
			}
		}

		/// <summary>
		/// Adds the given contact to this Account's personal contact list.
		/// </summary>
		/// <param name="i_ContactURI">The URI of a Contact.</param>
		public void AddPersonalContact(string i_ContactURI)
		{
			string[] ContactURIs = new string[] {i_ContactURI};
			int_AddPersonalContacts(ContactURIs);
		}

		/// <summary>
		/// Adds the given contacts to this Account's personal contact list.
		/// </summary>
		/// <param name="i_ContactURIs">Array of contact URIs.</param>
		public void AddPersonalContacts(string[] i_ContactURIs)
		{
			int_AddPersonalContacts(i_ContactURIs);
		}

		private void int_AddPersonalContacts(string[] i_ContactURIs)
		{
			//  Get initialized reference to web service
			GrooveContactsWebService.GrooveContacts ContactsWebService = this.GetInitializedContactsWebService(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_CONTACTS_URI);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to create contacts
			ContactsWebService.Create(i_ContactURIs);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("ContactsWebService::Create, " + TimeSpan.TotalMilliseconds + " ms");
			}
		}

		/// <summary>
		/// Returns an array of ContactDirectory objects representing the available contact directories for this Account.
		/// </summary>
		public GrooveWebServicesV12Helpers.ContactDirectory[] ContactDirectories
		{
			get
			{
				//  Get initialized reference to web service
				GrooveContactsWebService.GrooveContacts ContactsWebService = this.GetInitializedContactsWebService(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_CONTACTS_URI);

				System.DateTime BeginDateTime = System.DateTime.Now;

				//  Ask service to read directories
				GrooveWebServicesV12Helpers.GrooveContactsWebService.ContactDirectory[] ContactDirectories = ContactsWebService.ReadAvailableDirectories();

				if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
				{
					System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
					System.Diagnostics.Debug.WriteLine("ContactsWebService::ReadAvailableDirectories, " + TimeSpan.TotalMilliseconds + " ms");
				}

				System.Collections.ArrayList ContactDirectoryArrayList = new System.Collections.ArrayList();

				foreach (GrooveWebServicesV12Helpers.GrooveContactsWebService.ContactDirectory ContactDirectory in ContactDirectories)
				{
					GrooveWebServicesV12Helpers.ContactDirectory NewContactDirectory = new GrooveWebServicesV12Helpers.ContactDirectory
						(
						this,
						ContactDirectory
						);

					ContactDirectoryArrayList.Add(NewContactDirectory);
				}

				//  Return array from array list
				return (GrooveWebServicesV12Helpers.ContactDirectory[])ContactDirectoryArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.ContactDirectory));
			}
		}

		private GrooveContactsWebService.GrooveContacts GetInitializedContactsWebService(string i_TargetURI)
		{
            if ((m_GrooveContacts == null) || Context.ReinitNeeded(m_GrooveContacts.GrooveRequestHeaderValue.GrooveRequestKey))
			{
				m_GrooveContacts = GrooveWebServicesV12Helpers.Contact.CreateInitializedContactsWebService
					(
					m_IdentityURL,
					i_TargetURI,
					Context
					);
			}
			else
			{
				//  Explicitly overwrite target URL and Timeout
				m_GrooveContacts.Url = Context.Host + i_TargetURI;
                m_GrooveContacts.Timeout = Context.Timeout;
			}

			return m_GrooveContacts;
		}

		#endregion

		#region Contact Event Handling

		private void IncrementContactSubscriptionCount()
		{
			lock (s_ContactEventManagerSortedList)
			{
				if (m_ContactEventManagerCount == 0)
				{
					m_ContactSubscriptionID = GrooveWebServicesV12Helpers.EventManager.AddEventListener
						(
						Context,
						m_IdentityURL,
						GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_CONTACT_EVENT_CLASS, 
						this.ContactsURI,
						GrooveWebServicesV12Helpers.EventManager.s_EventURI,
						this
						);
				}

				++m_ContactEventManagerCount;
			}
		}

		private void DecrementContactSubscriptionCount()
		{
			lock (s_ContactEventManagerSortedList)
			{
				--m_ContactEventManagerCount;

				if (m_ContactEventManagerCount == 0)
				{
					GrooveWebServicesV12Helpers.EventManager.RemoveEventListener
						(
						m_ContactSubscriptionID,
						this
						);

					m_ContactSubscriptionID = null;
				}
			}
		}

		internal void RaiseContactAddedEvent(GrooveContactsWebService.Contact i_Contact)
		{
			if (InternalOnContactAddedEvent != null)
			{
				GrooveWebServicesV12Helpers.Contact Contact = new GrooveWebServicesV12Helpers.Contact
					(
					this, 
					i_Contact
					);

				InternalOnContactAddedEvent(Contact);
			}
		}

		internal void RaiseContactUpdatedEvent(GrooveContactsWebService.Contact i_Contact)
		{
			if (InternalOnContactUpdatedEvent != null)
			{
				GrooveWebServicesV12Helpers.Contact UpdatedContact = new GrooveWebServicesV12Helpers.Contact
					(
					this, 
					i_Contact
					);

				InternalOnContactUpdatedEvent(UpdatedContact);
			}
		}

		internal void RaiseContactRemovedEvent(string i_ContactURI)
		{
			if (InternalOnContactRemovedEvent != null)
				InternalOnContactRemovedEvent(i_ContactURI);
		}

		public delegate void OnContactAddedDelegate(GrooveWebServicesV12Helpers.Contact i_Contact);
		internal event OnContactAddedDelegate InternalOnContactAddedEvent;
		/// <summary>
		/// Event raised when a contact is added to the Account.
		/// </summary>
		public event OnContactAddedDelegate OnContactAddedEvent
		{
			add
			{
				IncrementContactSubscriptionCount();
				InternalOnContactAddedEvent += value;
			}
			remove
			{
				InternalOnContactAddedEvent -= value;
				DecrementContactSubscriptionCount();
			}
		}

		public delegate void OnContactUpdatedDelegate(GrooveWebServicesV12Helpers.Contact i_Contact);
		internal event OnContactUpdatedDelegate InternalOnContactUpdatedEvent;
		/// <summary>
		/// Event raised when a contact is updated in the Account.
		/// </summary>
		public event OnContactUpdatedDelegate OnContactUpdatedEvent
		{
			add
			{
				IncrementContactSubscriptionCount();
				InternalOnContactUpdatedEvent += value;
			}
			remove
			{
				InternalOnContactUpdatedEvent -= value;
				DecrementContactSubscriptionCount();
			}
		}

		public delegate void OnContactRemovedDelegate(string i_ContactURI);
		internal event OnContactRemovedDelegate InternalOnContactRemovedEvent;
		/// <summary>
		/// Event raised when a contact is removed from the Account.
		/// </summary>
		public event OnContactRemovedDelegate OnContactRemovedEvent
		{
			add
			{
				IncrementContactSubscriptionCount();
				InternalOnContactRemovedEvent += value;
			}
			remove
			{
				InternalOnContactRemovedEvent -= value;
				DecrementContactSubscriptionCount();
			}
		}

		#endregion

		#region Message Properties and Methods

		/// <summary>
		/// Returns the URI for raw access to Messages web services in this Account
		/// </summary>
		public string MessagesURI
		{
			get
			{
				return m_Account.Messages;
			}
		}

		/// <summary>
		/// Returns an array of all Messages in the account, including content and attachments.
		/// Marks the messages as "opened".
		/// </summary>
		public GrooveWebServicesV12Helpers.Message[] Messages
		{
			get
			{
				return this.GetMessages
					(
					true,											// IncludeContent
					true,											// IncludeAttachments
					true,											// MarkMessagesOpened
					GrooveWebServicesV12Helpers.Message.Category.All
					);
			}
		}

		/// <summary>
		/// Returns an array of all Messages in the given Category in the account, including content and attachments.
		/// Marks the messages as "opened".
		/// </summary>
		/// <param name="i_Category">Specifies the messages to retrieve: "All", "Sent", "Inbox", "New" or "Opened".</param>
		/// <returns>Array of Message objects</returns>
		public GrooveWebServicesV12Helpers.Message[] GetMessages(GrooveWebServicesV12Helpers.Message.Category i_Category)
		{
			return this.GetMessages
				(
				true,		// IncludeContent
				true,		// IncludeAttachments
				true,		// MarkMessagesOpened
				i_Category
				);
		}

		/// <summary>
		/// Returns an array of all Messages in the account, including attachments.
		/// Marks the messages as "opened".
		/// </summary>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <returns>Array of Message objects.</returns>
		public GrooveWebServicesV12Helpers.Message[] GetMessages(bool i_IncludeContent)
		{
			return this.GetMessages
				(
				i_IncludeContent,
				true,											// IncludeAttachments
				true,											// MarkMessagesOpened
				GrooveWebServicesV12Helpers.Message.Category.All
				);
		}

		/// <summary>
		/// Returns an array of all Messages in the given category in the account, including attachments.
		/// Marks the messages as "opened".
		/// </summary>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <param name="i_Category">Specifies the messages to retrieve: "All", "Sent", "Inbox", "New" or "Opened".</param>
		/// <returns>Array of Message objects.</returns>
		public GrooveWebServicesV12Helpers.Message[] GetMessages(bool i_IncludeContent, GrooveWebServicesV12Helpers.Message.Category i_Category)
		{
			return this.GetMessages
				(
				i_IncludeContent,
				true,				// IncludeAttachments
				true,				// MarkMessagesOpened
				i_Category
				);
		}

		/// <summary>
		/// Returns an array of all Messages in the account.
		/// Marks the messages as "opened".
		/// </summary>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <param name="i_IncludeAttachments">true to include attachments.</param>
		/// <returns>Array of Message objects.</returns>
		public GrooveWebServicesV12Helpers.Message[] GetMessages(bool i_IncludeContent, bool i_IncludeAttachments)
		{
			return this.GetMessages
				(
				i_IncludeContent,
				i_IncludeAttachments,
				true,	// MarkMessagesOpened
				GrooveWebServicesV12Helpers.Message.Category.All
				);
		}

		/// <summary>
		/// Returns an array of Messages in the account.
		/// </summary>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <param name="i_IncludeAttachments">true to include attachments.</param>
		/// <param name="i_MarkMessagesOpened">true to mark the messages as "opened".</param>
		/// <param name="i_Category">Specifies the messages to retrieve: "All", "Sent", "Inbox", "New" or "Opened".</param>
		/// <returns>Array of Message objects.</returns>
		public GrooveWebServicesV12Helpers.Message[] GetMessages(bool i_IncludeContent, bool i_IncludeAttachments, bool i_MarkMessagesOpened, GrooveWebServicesV12Helpers.Message.Category i_Category)
		{
			System.Collections.ArrayList MessageArrayList = new System.Collections.ArrayList();

			//  Get initialized reference to web service
			GrooveMessagesWebService.GrooveMessages MessagesWebService = this.GetInitializedMessagesWebService(this.MessagesURI);

			GrooveMessagesWebService.MessageCategory MessageCategory;
			switch (i_Category)
			{
				case GrooveWebServicesV12Helpers.Message.Category.All:
				{
					MessageCategory = GrooveMessagesWebService.MessageCategory.All;
					break;
				}

				case GrooveWebServicesV12Helpers.Message.Category.Inbox:
				{
					MessageCategory = GrooveMessagesWebService.MessageCategory.Inbox;
					break;
				}

				case GrooveWebServicesV12Helpers.Message.Category.New:
				{
					MessageCategory = GrooveMessagesWebService.MessageCategory.New;
					break;
				}

				case GrooveWebServicesV12Helpers.Message.Category.Opened:
				{
					MessageCategory = GrooveMessagesWebService.MessageCategory.Opened;
					break;
				}

				case GrooveWebServicesV12Helpers.Message.Category.Sent:
				{
					MessageCategory = GrooveMessagesWebService.MessageCategory.Sent;
					break;
				}

				default:
				{
					MessageCategory = GrooveMessagesWebService.MessageCategory.Unknown;
					break;
				}
			}

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to provide the list of Messages for this account
			GrooveMessagesWebService.Message[] Messages = MessagesWebService.Read
				(
				i_IncludeContent,
				true,					// IncludeContent specified
				i_IncludeAttachments,
				true,					// IncludeAttachments specified
				i_MarkMessagesOpened,
				true,					// MarkMessagesOpened specified
				MessageCategory,
				true					// MessageCategory specified
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("MessagesWebService::Read, " + TimeSpan.TotalMilliseconds + " ms");
			}

			//  Populate array list of Messages
			foreach (GrooveMessagesWebService.Message Message in Messages)
			{
				GrooveWebServicesV12Helpers.Message NewMessage = new GrooveWebServicesV12Helpers.Message
					(
					this,
					Message
					);

				MessageArrayList.Add(NewMessage);
			}

			//  Return array from array list
			return (GrooveWebServicesV12Helpers.Message[])MessageArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Message));
		}

		/// <summary>
		/// Opens a single message in the Account.
		/// </summary>
		/// <param name="i_MessageURI">URI of the Message.</param>
		/// <returns>Message</returns>
		public GrooveWebServicesV12Helpers.Message OpenMessage(string i_MessageURI)
		{
			return this.OpenMessage
				(
				i_MessageURI,
				true,	// IncludeContent
				true,	// IncludeAttachments
				true	// MarkMessagesOpened
				);
		}

		/// <summary>
		/// Opens a single message in the Account.
		/// </summary>
		/// <param name="i_MessageURI">URI of the Message.</param>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <returns>Message</returns>
		public GrooveWebServicesV12Helpers.Message OpenMessage(string i_MessageURI, bool i_IncludeContent)
		{
			return this.OpenMessage
				(
				i_MessageURI,
				i_IncludeContent,
				true,	// IncludeAttachments
				true	// MarkMessagesOpened
				);
		}

		/// <summary>
		/// Opens a single message in the Account.
		/// </summary>
		/// <param name="i_MessageURI">URI of the Message.</param>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <param name="i_IncludeAttachments">true to include attachments.</param>
		/// <returns>Message</returns>
		public GrooveWebServicesV12Helpers.Message OpenMessage(string i_MessageURI, bool i_IncludeContent, bool i_IncludeAttachments)
		{
			return this.OpenMessage
				(
				i_MessageURI,
				i_IncludeContent,
				i_IncludeAttachments,
				true	// MarkMessagesOpened
				);
		}

		/// <summary>
		/// Opens a single message in the Account.
		/// </summary>
		/// <param name="i_MessageURI">URI of the Message.</param>
		/// <param name="i_IncludeContent">true to include the message content.</param>
		/// <param name="i_IncludeAttachments">true to include attachments.</param>
		/// <param name="i_MarkMessagesOpened">true to mark the message "opened".</param>
		/// <returns>Message</returns>
		/// <summary>
		public GrooveWebServicesV12Helpers.Message OpenMessage(string i_MessageURI, bool i_IncludeContent, bool i_IncludeAttachments, bool i_MarkMessagesOpened)
		{
			//  Get initialized reference to web service
			GrooveMessagesWebService.GrooveMessages MessagesWebService = this.GetInitializedMessagesWebService(i_MessageURI);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to provide the list of Messages for this account
			GrooveMessagesWebService.Message Message = MessagesWebService.ReadMessage
				(
				i_IncludeContent,
				true,					// IncludeContent specified
				i_IncludeAttachments,
				true,					// IncludeAttachments specified
				i_MarkMessagesOpened,
				true					// MarkMessagesOpened specified
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("MessagesWebService::ReadMessage, " + TimeSpan.TotalMilliseconds + " ms");
			}

			GrooveWebServicesV12Helpers.Message NewMessage = new GrooveWebServicesV12Helpers.Message
				(
				this,
				Message
				);

			return NewMessage;
		}

		/// <summary>
		/// Delete a single Message in the Account, on all endpoints belonging to the account.
		/// </summary>
		/// <param name="i_MessageURI">URI of the Message.</param>
		public void DeleteMessage(string i_MessageURI)
		{
			string[] MessageURIs = new string[] {i_MessageURI};

			this.DeleteMessages
				(
				MessageURIs,
				true			// OnAllEndpoints
				);
		}

		/// <summary>
		/// Delete a single Message in the Account.
		/// </summary>
		/// <param name="i_MessageURI">URI of the Message.</param>
		/// <param name="i_OnAllEndpoints">true to delete the message on all endpoints belonging to the account. false to delete the message just on the endpoint acting as the web services server.</param>
		public void DeleteMessage(string i_MessageURI, bool i_OnAllEndpoints)
		{
			string[] MessageURIs = new string[] {i_MessageURI};

			this.DeleteMessages
				(
				MessageURIs,
				i_OnAllEndpoints
				);
		}

		/// <summary>
		/// Delete a set of messages in the Account.
		/// </summary>
		/// <param name="i_MessageURIs">Array of URIs of the Messages.</param>
		public void DeleteMessages(string[] i_MessageURIs)
		{
			this.DeleteMessages
				(
				i_MessageURIs,
				true			// OnAllEndpoints
				);
		}

		/// <summary>
		/// Delete a set of messages in the Account.
		/// </summary>
		/// <param name="i_MessageURIs">Array of URIs of the Messages.</param>
		/// <param name="i_OnAllEndpoints">true to delete the message on all endpoints belonging to the account. false to delete the message just on the endpoint acting as the web services server.</param>
		public void DeleteMessages(string[] i_MessageURIs, bool i_OnAllEndpoints)
		{
			//  Get initialized reference to web service
			GrooveMessagesWebService.GrooveMessages MessagesWebService = this.GetInitializedMessagesWebService(this.MessagesURI);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to provide the list of Messages for this account
			MessagesWebService.Delete
				(
				i_MessageURIs,
				i_OnAllEndpoints,
				true				// OnAllEndpoints specified
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("MessagesWebService::Delete, " + TimeSpan.TotalMilliseconds + " ms");
			}
		}

		private GrooveMessagesWebService.GrooveMessages GetInitializedMessagesWebService(string i_TargetURI)
		{
            if ((m_GrooveMessages == null) || Context.ReinitNeeded(m_GrooveMessages.GrooveRequestHeaderValue.GrooveRequestKey))
			{
				m_GrooveMessages = GrooveWebServicesV12Helpers.Message.CreateInitializedMessagesWebService
					(
					m_IdentityURL,
					i_TargetURI,
					Context
					);
			}
			else
			{
				//  Explicitly overwrite target URL and Timeout
				m_GrooveMessages.Url = Context.Host + i_TargetURI;
                m_GrooveMessages.Timeout = Context.Timeout;
			}

			return m_GrooveMessages;
		}

		#endregion

		#region Message Event Handling

		private void IncrementMessageSubscriptionCount()
		{
			lock (s_MessageEventManagerSortedList)
			{
				if (m_MessageEventManagerCount == 0)
				{
					m_MessageSubscriptionID = GrooveWebServicesV12Helpers.EventManager.AddEventListener
						(
						Context,
						m_IdentityURL,
						GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_MESSAGE_EVENT_CLASS, 
						this.MessagesURI,
						GrooveWebServicesV12Helpers.EventManager.s_EventURI,
						this
						);
				}

				++m_MessageEventManagerCount;
			}
		}

		private void DecrementMessageSubscriptionCount()
		{
			lock (s_MessageEventManagerSortedList)
			{
				--m_MessageEventManagerCount;

				if (m_MessageEventManagerCount == 0)
				{
					GrooveWebServicesV12Helpers.EventManager.RemoveEventListener
						(
						m_MessageSubscriptionID,
						this
						);

					m_MessageSubscriptionID = null;
				}
			}
		}

		internal void RaiseMessageReceivedEvent(GrooveMessagesWebService.MessageHeader i_MessageHeader)
		{
			if (InternalOnMessageReceivedEvent != null)
			{
				GrooveWebServicesV12Helpers.MessageHeader MessageHeader = new GrooveWebServicesV12Helpers.MessageHeader
					(
					this, 
					i_MessageHeader
					);

				InternalOnMessageReceivedEvent(MessageHeader);
			}
		}

		internal void RaiseMessageOpenedEvent(GrooveMessagesWebService.MessageHeader i_MessageHeader)
		{
			if (InternalOnMessageOpenedEvent != null)
			{
				GrooveWebServicesV12Helpers.MessageHeader MessageHeader = new GrooveWebServicesV12Helpers.MessageHeader
					(
					this, 
					i_MessageHeader
					);

				InternalOnMessageOpenedEvent(MessageHeader);
			}
		}

		internal void RaiseMessageSentEvent(GrooveMessagesWebService.MessageHeader i_MessageHeader)
		{
			if (InternalOnMessageSentEvent != null)
			{
				GrooveWebServicesV12Helpers.MessageHeader MessageHeader = new GrooveWebServicesV12Helpers.MessageHeader
					(
					this, 
					i_MessageHeader
					);

				InternalOnMessageSentEvent(MessageHeader);
			}
		}


		internal void RaiseMessageRemovedEvent(string i_MessageURI)
		{
			if (InternalOnMessageRemovedEvent != null)
				InternalOnMessageRemovedEvent(i_MessageURI);
		}

		public delegate void OnMessageReceivedDelegate(GrooveWebServicesV12Helpers.MessageHeader i_MessageHeader);
		internal event OnMessageReceivedDelegate InternalOnMessageReceivedEvent;
		/// <summary>
		/// Event raised when an instant message is received by the Account.
		/// </summary>
		public event OnMessageReceivedDelegate OnMessageReceivedEvent
		{
			add
			{
				IncrementMessageSubscriptionCount();
				InternalOnMessageReceivedEvent += value;
			}
			remove
			{
				InternalOnMessageReceivedEvent -= value;
				DecrementMessageSubscriptionCount();
			}
		}

		public delegate void OnMessageOpenedDelegate(GrooveWebServicesV12Helpers.MessageHeader i_MessageHeader);
		internal event OnMessageOpenedDelegate InternalOnMessageOpenedEvent;
		/// <summary>
		/// Event raised when an instant message is opened in the Account.
		/// </summary>
		public event OnMessageOpenedDelegate OnMessageOpenedEvent
		{
			add
			{
				IncrementMessageSubscriptionCount();
				InternalOnMessageOpenedEvent += value;
			}
			remove
			{
				InternalOnMessageOpenedEvent -= value;
				DecrementMessageSubscriptionCount();
			}
		}

		public delegate void OnMessageSentDelegate(GrooveWebServicesV12Helpers.MessageHeader i_MessageHeader);
		internal event OnMessageSentDelegate InternalOnMessageSentEvent;
		/// <summary>
		/// Event raised when an instant message is sent in the Account.
		/// </summary>
		public event OnMessageSentDelegate OnMessageSentEvent
		{
			add
			{
				IncrementMessageSubscriptionCount();
				InternalOnMessageSentEvent += value;
			}
			remove
			{
				InternalOnMessageSentEvent -= value;
				DecrementMessageSubscriptionCount();
			}
		}

		public delegate void OnMessageRemovedDelegate(string i_MessageURI);
		internal event OnMessageRemovedDelegate InternalOnMessageRemovedEvent;
		/// <summary>
		/// Event raised when an instant message is deleted in the Account.
		/// </summary>
		public event OnMessageRemovedDelegate OnMessageRemovedEvent
		{
			add
			{
				IncrementMessageSubscriptionCount();
				InternalOnMessageRemovedEvent += value;
			}
			remove
			{
				InternalOnMessageRemovedEvent -= value;
				DecrementMessageSubscriptionCount();
			}
		}

		#endregion

		#region GrooveWebServicesV12HelpersBase Implementation
	
		public override string BindableURL
		{
			get
			{
				if (System.String.IsNullOrEmpty(m_BindableURL))
					m_BindableURL = GrooveWebServicesV12Helpers.BindServices.GWSH_PROTOCOL + this.URI;

				return m_BindableURL;
			}
		}

		public override object BindToObject(ref string[] i_URLParts, int i_URLPartIndex)
		{
			object BindResult = null;
			string RelativeURL = i_URLParts[i_URLPartIndex];
			string[] RelativeURLParts = RelativeURL.Split(new char[]{'#'});

			string ObjectType = RelativeURLParts[0];

			if (ObjectType == "Identity")
			{
				string IdentityURI = "grooveIdentity://" + RelativeURLParts[1];
				
				GrooveWebServicesV12Helpers.Identity[] Identities = this.Identities;
				foreach (GrooveWebServicesV12Helpers.Identity Identity in Identities)
				{
					if (Identity.URI == IdentityURI)
					{
						BindResult = Identity;
						break;
					}
				}

				if (BindResult == null)
					throw new System.Exception("Unable to find identity '" + IdentityURI +"'");

				//  If there are more url parts, continue binding
				if (i_URLParts.Length > ++i_URLPartIndex)
				{
					GrooveWebServicesV12Helpers.IBindServices IBindServices = (GrooveWebServicesV12Helpers.IBindServices)BindResult;
					BindResult = IBindServices.BindToObject(ref i_URLParts, i_URLPartIndex);
				}
			}
			else if (ObjectType == "Contact")
			{
				string ContactURI = "grooveIdentity://" + RelativeURLParts[1];
				
				GrooveWebServicesV12Helpers.Contact[] Contacts = this.PersonalContacts;
				foreach (GrooveWebServicesV12Helpers.Contact Contact in Contacts)
				{
					//  If we find matching contact return it since no binding occurs past it
					if (Contact.URI == ContactURI)
					{
						BindResult = Contact;
						break;
					}
				}

				if (BindResult == null)
					throw new System.Exception("Unable to find contact '" + ContactURI +"'");
			}
			else
				throw new System.Exception("Unknown account url part - '" + ObjectType + "'");

			return BindResult;
		}

		#endregion
	
		#region IGrooveWebServicesEventCallback Members

		public void ProcessEvent(GrooveEventsWebService.Event i_Event)
		{
			switch (i_Event.EventType)
			{
				case GrooveWebServicesV12Helpers.Shared.GROOVE_CONTACT_ADD_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveContactAddEventData ContactAddEventData = (GrooveEventsWebService.GrooveContactAddEventData)i_Event.EventData;
					this.RaiseContactAddedEvent(ContactAddEventData.Contact);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_CONTACT_DELETE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveContactDeleteEventData ContactDeleteEventData = (GrooveEventsWebService.GrooveContactDeleteEventData)i_Event.EventData;
					this.RaiseContactRemovedEvent(ContactDeleteEventData.ContactURI);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_CONTACT_UPDATE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveContactUpdateEventData ContactUpdateEventData = (GrooveEventsWebService.GrooveContactUpdateEventData)i_Event.EventData;
					this.RaiseContactUpdatedEvent(ContactUpdateEventData.Contact);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_MESSAGE_DELETE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveMessageDeleteEventData MessageDeleteEventData = (GrooveEventsWebService.GrooveMessageDeleteEventData)i_Event.EventData;
					this.RaiseMessageRemovedEvent(MessageDeleteEventData.MessageURI);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_MESSAGE_OPENED_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveMessageOpenedEventData MessageOpenedEventData = (GrooveEventsWebService.GrooveMessageOpenedEventData)i_Event.EventData;
					this.RaiseMessageOpenedEvent(MessageOpenedEventData.MessageHeader);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_MESSAGE_SENT_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveMessageSentEventData MessageSentEventData = (GrooveEventsWebService.GrooveMessageSentEventData)i_Event.EventData;
					this.RaiseMessageSentEvent(MessageSentEventData.MessageHeader);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_MESSAGE_RECEIVED_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveMessageReceivedEventData MessageReceivedEventData = (GrooveEventsWebService.GrooveMessageReceivedEventData)i_Event.EventData;
					this.RaiseMessageReceivedEvent(MessageReceivedEventData.MessageHeader);

					break;
				}

				default:
				{
					System.Diagnostics.Debug.WriteLine("[Account]Unknown event type: " + i_Event.EventType);
					break;
				}
			}
		}

		#endregion
	}
}
